package lime2;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.util.logging.Logger;
import lights.interfaces.ITuple;

public abstract class LimeTSMgr {
	public static boolean useReactionTree = false;
	public static boolean useSingleThread = false;

	protected static Hashtable ltsms = new Hashtable();
	private static long rids = -1;
	protected String name;
	protected byte policy;
	protected Hashtable weak = new Hashtable(100);
	protected Hashtable strong = new Hashtable(100);
	protected boolean weak_running = false;
	protected boolean interrupt = false;
	protected Logger logger;

	/**
	 * Returns the LimeTSMgr corresponding to the given LimeTupleSpace name.
	 * 
	 * @param name
	 *            of LimeTupleSpace
	 * @return corresponding LimeTSMgr (<code>null</code> if it doesn't exist)
	 */
	static LimeTSMgr get(String name) {
		return (LimeTSMgr) ltsms.get(name);
	}

	public LimeTSMgr() {
		super();
	}

	/**
	 * Returns the name of the managed tuplespace.
	 * 
	 * @return name of the managed tuplespace
	 */
	protected String getName() {
		return name;
	}

	/**
	 * Returns the policy of the managed tuplespace.
	 * 
	 * @return policy
	 */
	protected byte getPolicy() {
		return policy;
	}

	/**
	 * Deregisters strong reactions.
	 * 
	 * @param ids
	 *            identifiers of the strong reactions to deregister
	 * @return boolean[], where <code>boolean[i]</code> is <code>true</code> if
	 *         reaction <code>i</code> was successfully deregistered,
	 *         <code>false</code> otherwise
	 */
	protected abstract boolean[] deregisterStrong(ReactionID[] ids);

	/**
	 * Registers weak reactions.
	 * 
	 * @param r
	 *            array of weak reactions to install
	 * @param ids
	 *            array of the corresponding reaction identifiers
	 * @return the (same) reaction identifiers
	 */
	protected synchronized ReactionID[] registerWeak(Reaction[] r,
			ReactionID[] ids) {
		// previous parameter checking guarantees r not to be null
		// LocalOpMgr guarantees ids to be a valid array of ids (not null, same
		// length of r, etc..)
		RegisteredReaction[] rr = new RegisteredReaction[r.length];
		for (int i = 0; i < r.length; i++) {
			rr[i] = new RegisteredReaction(r[i], ids[i]);
			weak.put(ids[i], rr[i]);
		}
		return ids;
	}

	/**
	 * Deregisters weak reactions.
	 * 
	 * @param ids
	 *            identifiers of the weak reactions to deregister
	 * @return boolean[], where <code>boolean[i]</code> is <code>true</code> if
	 *         reaction <code>i</code> was successfully deregistered,
	 *         <code>false</code> otherwise
	 */
	protected synchronized boolean[] deregisterWeak(ReactionID ids[]) {
		// previous parameter checking guarantees ids not to be null
		boolean[] ret = new boolean[ids.length];
		for (int i = 0; i < ids.length; i++)
			ret[i] = (weak.remove(ids[i]) != null) ? true : false;
		return ret;
	}

	/**
	 * Returns a specific registered strong reaction.
	 * 
	 * @param id
	 *            identifier of the strong reaction
	 * @return corresponding (strong) registered reaction, <code>null</code> if
	 *         it is not registered
	 */
	protected synchronized RegisteredReaction getStrong(ReactionID id) {
		return (RegisteredReaction) strong.get(id);
	}

	/**
	 * Returns a specific registered weak reaction.
	 * 
	 * @param id
	 *            identifier of the weak reaction
	 * @return corresponding (weak) registered reaction, <code>null</code> if it
	 *         is not registered
	 */
	protected synchronized RegisteredReaction getWeak(ReactionID id) {
		return (RegisteredReaction) weak.get(id);
	}

	/**
	 * Returns all the registered strong reactions.
	 * 
	 * @return all the registered strong reactions
	 */
	protected synchronized RegisteredReaction[] getAllStrong() {
		RegisteredReaction[] ret = new RegisteredReaction[strong.size()];
		int i = 0;
		for (Enumeration e = strong.elements(); e.hasMoreElements();)
			ret[i++] = (RegisteredReaction) e.nextElement();
		return ret;
	}

	/**
	 * Returns all the strong reactions registered by the given host.
	 * 
	 * @param x
	 *            given host
	 * @return all the registered strong reactions
	 */
	protected synchronized RegisteredReaction[] getAllStrong(LimeServerID x) {
		Vector wtmp = new Vector();
		for (Enumeration e = strong.elements(); e.hasMoreElements();) {
			RegisteredReaction rrtmp = (RegisteredReaction) e.nextElement();
			if (rrtmp.getReactionID().getCreationHost().equals(x))
				wtmp.addElement(rrtmp);
		}
		RegisteredReaction[] ret = new RegisteredReaction[wtmp.size()];
		wtmp.copyInto(ret);
		return ret;
	}

	/**
	 * Returns all the registered weak reactions.
	 * 
	 * @return all the registered weak reactions
	 */
	protected synchronized RegisteredReaction[] getAllWeak() {
		RegisteredReaction[] ret = new RegisteredReaction[weak.size()];
		int i = 0;
		for (Enumeration e = weak.elements(); e.hasMoreElements();)
			ret[i++] = (RegisteredReaction) e.nextElement();
		return ret;
	}

	/**
	 * Returns a bunch of unique identifiers for "pure strong" reactions (they
	 * are stand-alone strong reactions, not strong parts of weak reactions). <br>
	 * The numeric identifier of the first ReactionID created on this host is
	 * zero. Synchronization is necessary since multiple threads (LocalOpMgrs..)
	 * could try to access the global counter ("rids") when we are in the middle
	 * of a previous invocation of this method (.. this would ruin uniqueness of
	 * reaction identifiers).
	 * 
	 * @param h
	 *            number of reaction identifiers to return
	 * @return bunch of valid reaction identifiers
	 */
	protected synchronized ReactionID[] nextPureStrongRID(int h) {
		ReactionID[] ret = new ReactionID[h];
		for (int i = 0; i < h; i++) {
			rids++;
			ret[i] = new ReactionID(Location.HERE.getID(), rids, null, null,
					null, true); // null: see class ReactionID
		}
		return ret;
	}

	/**
	 * Returns a bunch of identifiers for strong parts of weak reactions.
	 * 
	 * @param h
	 *            number of reaction identifiers to return
	 * @return bunch of valid reaction identifiers
	 */
	protected synchronized ReactionID[] nextStrongRID(int h) {
		ReactionID[] ret = new ReactionID[h];
		for (int i = 0; i < h; i++) {
			rids++;
			ret[i] = new ReactionID(Location.HERE.getID(), rids, null, null,
					null, false); // null: see class ReactionID
		}
		return ret;
	}

	/**
	 * Creates a bunch of identifiers for weak parts of weak reactions: it
	 * re-uses identifiers of the corresponding strong parts. The returned IDs
	 * are different from the given ones because they store reconciliation
	 * information; the given ones are NOT affected.
	 * 
	 * @param ri
	 *            reaction identifiers to re-use
	 * @param rs
	 *            corresponding reactions
	 * @return bunch of valid reaction identifiers
	 */
	protected ReactionID[] createWeakRID(ReactionID[] ri, Reaction[] rs) {
		ReactionID[] ret = new ReactionID[ri.length];
		for (int i = 0; i < ri.length; i++)
			ret[i] = new ReactionID(Location.HERE.getID(), ri[i]
					.getNumericIdentifier(), name, LimeWrapper.getCur(rs[i]
					.getTemplate()), rs[i], false);
		return ret;
	}

	/**
	 * Returns whether we are within the execution of (the listener of) a strong
	 * or weak reaction.
	 * 
	 * @return boolean
	 */
	protected abstract boolean isWithinReaction();

	/**
	 * Delegates to: Reactor.doRead (.. only if we are within a reaction !)
	 * 
	 * @param t
	 *            ITuple
	 * @return ITuple
	 */
	protected abstract ITuple doRead(ITuple t);

	/**
	 * Delegates to: Reactor.doReadg (.. only if we are within a reaction !)
	 * 
	 * @param t
	 *            ITuple
	 * @return array of ITuples
	 */
	protected abstract ITuple[] doReadg(ITuple t);

	/**
	 * Delegates to: Reactor.doTake (.. only if we are within a reaction !)
	 * 
	 * @param t
	 *            ITuple
	 * @return ITuple
	 */
	protected abstract ITuple doTake(ITuple t);
	
	/**
	 * Replace a old tuple with the new one, you must guarantee the
	 * consistency of the removed tuple and the new tuple
	 * @param template
	 * 		the template to choose the tuple to be removed
	 * @param t
	 * @return
	 * 		the tuple is replaced
	 * @author Xing Jiankuan
	 */
	abstract protected ITuple doUpdate(ITuple template, ITuple t); 
	

	
	
	/**
	 * Delegates to: Reactor.doTakeg (.. only if we are within a reaction !)
	 * 
	 * @param t
	 *            ITuple
	 * @return array of ITuples
	 */
	protected abstract ITuple[] doTakeg(ITuple t);

	protected abstract void doWrite(ITuple[] t);

	protected abstract void fireWeak(ReactionID id, ReactionEvent re);

	protected abstract ReactionID[] registerStrong(Reaction[] r,
			ReactionID[] ids);

	static LimeTSMgr creatLTSM(String name, byte policy) {
		if (useReactionTree) {
			return new OptimizedLimeTSMgr(name, policy);
		} else {
			if (useSingleThread)
				return new OriginalLimeTSMgr(name, policy);
			else
				return new OriginalLimeTSMgr(name, policy);
		}
	}
}